//
//  GlobalMethod+Device.m
//  MexicoLoan
//
//  Created by WXP on 2025/2/26.
//

#import "GlobalMethod+Device.h"
#import <AdSupport/AdSupport.h>
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <AVFoundation/AVFoundation.h>
#import <mach/mach_time.h>
#import <mach/mach.h>
#import <sys/sysctl.h>
#import <sys/utsname.h>
#import <AdjustSdk/AdjustSdk.h>

@implementation GlobalMethod (Device)

#pragma mark - 获取APP版本号
+ (NSString *)getVersion{
    NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
    NSString *appVersion = [infoDic objectForKey:@"CFBundleShortVersionString"];
    return appVersion;
}

#pragma mark - 获取 APP 构建版本号
+ (NSString *)getBundleVersion{
    NSBundle *mainBundle = [NSBundle mainBundle];
    NSString *buildVersion = [mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
    return buildVersion;
}

#pragma mark - 获取APP名字
+ (NSString *)getAppName{
    NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
    NSString *appName = [infoDic objectForKey:@"CFBundleDisplayName"];
    return appName;
}

#pragma mark - 获取包名
+ (NSString *)getBundleIdentifier{
    NSString * bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
    bundleIdentifier = @"com.ios.mx.ui29";
    return bundleIdentifier;
}

#pragma mark - 获取iPhone型号名称
+ (NSString *)getDeviceModelName{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *deviceModel = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];

    NSDictionary *modelMapping = @{
        // iPhone 16 系列 (预测标识符，实际可能不同)
        @"iPhone17,1": @"iPhone 16",
        @"iPhone17,2": @"iPhone 16 Plus",
        @"iPhone17,3": @"iPhone 16 Pro",
        @"iPhone17,4": @"iPhone 16 Pro Max",
        
        // iPhone 15 系列
        @"iPhone15,4": @"iPhone 15",
        @"iPhone15,5": @"iPhone 15 Plus",
        @"iPhone16,1": @"iPhone 15 Pro",
        @"iPhone16,2": @"iPhone 15 Pro Max",
        
        // iPhone 14 系列
        @"iPhone14,7": @"iPhone 14",
        @"iPhone14,8": @"iPhone 14 Plus",
        @"iPhone15,2": @"iPhone 14 Pro",
        @"iPhone15,3": @"iPhone 14 Pro Max",
        
        // iPhone 13 系列
        @"iPhone14,4": @"iPhone 13 mini",
        @"iPhone14,5": @"iPhone 13",
        @"iPhone14,2": @"iPhone 13 Pro",
        @"iPhone14,3": @"iPhone 13 Pro Max",
        
        // iPhone 12 系列
        @"iPhone13,1": @"iPhone 12 mini",
        @"iPhone13,2": @"iPhone 12",
        @"iPhone13,3": @"iPhone 12 Pro",
        @"iPhone13,4": @"iPhone 12 Pro Max",
        
        // iPhone 11 系列
        @"iPhone12,1": @"iPhone 11",
        @"iPhone12,3": @"iPhone 11 Pro",
        @"iPhone12,5": @"iPhone 11 Pro Max",
        
        // iPhone X 系列
        @"iPhone10,3": @"iPhone X",
        @"iPhone10,6": @"iPhone X",
        @"iPhone11,2": @"iPhone XS",
        @"iPhone11,4": @"iPhone XS Max",
        @"iPhone11,6": @"iPhone XS Max",
        @"iPhone11,8": @"iPhone XR",
        
        // iPhone 8 系列
        @"iPhone10,1": @"iPhone 8",
        @"iPhone10,4": @"iPhone 8",
        @"iPhone10,2": @"iPhone 8 Plus",
        @"iPhone10,5": @"iPhone 8 Plus",
        
        // iPhone 7 系列
        @"iPhone9,1": @"iPhone 7",
        @"iPhone9,3": @"iPhone 7",
        @"iPhone9,2": @"iPhone 7 Plus",
        @"iPhone9,4": @"iPhone 7 Plus",
        
        // iPhone 6 系列
        @"iPhone7,2": @"iPhone 6",
        @"iPhone7,1": @"iPhone 6 Plus",
        @"iPhone8,1": @"iPhone 6s",
        @"iPhone8,2": @"iPhone 6s Plus",
        @"iPhone8,4": @"iPhone SE",
        
        // iPhone SE 系列
        @"iPhone12,8": @"iPhone SE",
        @"iPhone14,6": @"iPhone SE",
        
        // iPad 系列 (部分示例)
        @"iPad11,1": @"iPad mini 5",
        @"iPad11,2": @"iPad mini 5",
        @"iPad13,1": @"iPad Air 4",
        @"iPad13,2": @"iPad Air 4",
        
        // iPod touch
        @"iPod9,1": @"iPod touch"
    };
    
    NSString *modelName = modelMapping[deviceModel];
    return modelName ?: deviceModel;
}

#pragma mark - 获取屏幕尺寸  iPhone 12  6.1英寸
+ (NSString *)getScreenDiagonalSize {
    float scale = [[UIScreen mainScreen] scale];
    float ppi = scale * (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ? 132 : 163);
    float width = ([[UIScreen mainScreen] bounds].size.width * scale);
    float height = ([[UIScreen mainScreen] bounds].size.height * scale);
    float horizontal = width / ppi, vertical = height / ppi;
    float diagonal = sqrt(pow(horizontal, 2) + pow(vertical, 2));
    return [NSString stringWithFormat:@"%.8f",diagonal];
}

#pragma mark - 获取ADID
+ (NSString *)getAdid{
    NSString * adid = [GlobalMethod readUnprefixStrFromUserDefaults:LOCAL_ADID];
    if(isStr(adid)){
        return adid;
    }else{
        // 创建一个新的adid
        [Adjust adidWithCompletionHandler:^(NSString * _Nullable adid) {
            [GlobalMethod writeUnprefixStr:adid forKey:LOCAL_ADID];
        }];
        
        NSString * adid = @"";
        if(isStr(adid)){
            [GlobalMethod writeUnprefixStr:adid forKey:LOCAL_ADID];
            return adid;
        }else{
            return @"";
        }
    }
}

#pragma mark - 获取IDFA
+ (NSString *)getIDFA{
    NSString * idfa = [GlobalMethod readUnprefixStrFromUserDefaults:LOCAL_IDFA];
    NSRange adidRange = [idfa rangeOfString:@"0000-0000-0000"];
    if (adidRange.location != NSNotFound){
        idfa = @"";
    }
    if(isStr(idfa)){
        [GlobalMethod writeUnprefixStr:idfa forKey:LOCAL_IDFA];
        return idfa;
    }else{
        NSString *advertisingIdentifier = [GlobalMethod getAdvertisingIdentifier];
        [GlobalMethod writeUnprefixStr:advertisingIdentifier forKey:LOCAL_IDFA];
        return advertisingIdentifier;
    }
}

+ (NSString *)getAdvertisingIdentifier {
    // 主线程调用
    __block NSString *advertisingIdentifier = @"";
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    if (@available(iOS 14, *)) {
        [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
            switch (status) {
                case ATTrackingManagerAuthorizationStatusAuthorized:
                    // NSLog(@"用户允许广告追踪");
                    if ([GlobalMethod readBoolLocal:LOCAL_AGREE_IDFA_AUTH] == false) {
                        [GlobalMethod writeBool:true local:LOCAL_AGREE_IDFA_AUTH];
                        [GlobalMethod hitPointWithPageName:KEY_Idfa action:KEY_agreeIdfaAuth extInfo:nil];
                    }
                    advertisingIdentifier = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
                    break;
                case ATTrackingManagerAuthorizationStatusDenied:
                case ATTrackingManagerAuthorizationStatusRestricted:
                    // NSLog(@"用户拒绝广告追踪");
                    if ([GlobalMethod readBoolLocal:LOCAL_REFUSE_IDFA_AUTH] == false) {
                        [GlobalMethod writeBool:true local:LOCAL_REFUSE_IDFA_AUTH];
                        [GlobalMethod hitPointWithPageName:KEY_Idfa action:KEY_refuseIdfaAuth extInfo:nil];
                    }
                    advertisingIdentifier = @"";
                    break;
                case ATTrackingManagerAuthorizationStatusNotDetermined:
                    // 用户尚未做出选择
                    // 不会执行到这里，因为弹窗只会返回允许或拒绝
                    break;
            }
            // 处理授权状态的代码
            dispatch_semaphore_signal(semaphore);
        }];
    }
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return advertisingIdentifier;
}

#pragma mark - 获取 deviceNo
+ (NSString *)getDeviceNo{
    NSString * deviceNo = [GlobalMethod readUnprefixStrFromUserDefaults:LOCAL_DEVICE_NO];
    if(isStr(deviceNo)){
        return deviceNo;
    }else{
        // 创建一个新的 deviceNo
        NSString * deviceNo = [[UIDevice currentDevice] identifierForVendor].UUIDString;
        [GlobalMethod writeUnprefixStr:deviceNo forKey:LOCAL_DEVICE_NO];
        return deviceNo;
    }
}

#pragma mark - 获取 globallyUniqueString
// 8-4-4-4-12-4-16
+ (NSString *)getGloballyUniqueString{
    // 先生成一个标准 UUID（长度 32 个十六进制字符，不含连字符）
    NSString *uuidString = [[NSUUID UUID] UUIDString];
    uuidString = [uuidString stringByReplacingOccurrencesOfString:@"-" withString:@""];
    
    // 确保 UUID 足够长（8+4+4+4+12+4+16 = 52）
    // 如果不够，可以拼接两个 UUID
    while (uuidString.length < 52) {
        NSString *extraUUID = [[[NSUUID UUID] UUIDString] stringByReplacingOccurrencesOfString:@"-" withString:@""];
        uuidString = [uuidString stringByAppendingString:extraUUID];
    }

    // 截取每一段
    NSString *part1 = [uuidString substringWithRange:NSMakeRange(0, 8)];
    NSString *part2 = [uuidString substringWithRange:NSMakeRange(8, 4)];
    NSString *part3 = [uuidString substringWithRange:NSMakeRange(12, 4)];
    NSString *part4 = [uuidString substringWithRange:NSMakeRange(16, 4)];
    NSString *part5 = [uuidString substringWithRange:NSMakeRange(20, 12)];
    NSString *part6 = [uuidString substringWithRange:NSMakeRange(32, 4)];
    NSString *part7 = [uuidString substringWithRange:NSMakeRange(36, 16)];
    
    // 拼接为目标格式
    NSString *customUUID = [NSString stringWithFormat:@"%@-%@-%@-%@-%@-%@-%@", part1, part2, part3, part4, part5, part6, part7];

    return customUUID;
}

#pragma mark - 获取手机 内存大小
// 获取手机 总内存大小
+ (NSString *)getDeviceTotalMemory {
    int mib[2];
    mib[0] = CTL_HW;
    mib[1] = HW_MEMSIZE;
    unsigned long long physicalMemory;
    size_t length = sizeof(physicalMemory);
    if (sysctl(mib, 2, &physicalMemory, &length, NULL, 0) == 0) {
        return [NSString stringWithFormat:@"%llu", physicalMemory];
    } else {
        return @"";
    }
}

// 获取手机 空闲内存大小
+ (NSString *)getDeviceFreeMemory {
    mach_port_t hostPort = mach_host_self();
    vm_statistics64_data_t vmStats;
    mach_msg_type_number_t count = sizeof(vmStats) / sizeof(natural_t);
    if (KERN_SUCCESS == host_statistics64(hostPort, HOST_VM_INFO64, (host_info64_t)&vmStats, &count)) {
        vm_size_t pageSize = vm_page_size;
        uint64_t freeMemory = (uint64_t)vmStats.free_count * pageSize;
        return [NSString stringWithFormat:@"%llu", freeMemory];
    } else {
        return @"";
    }
}

// 获取手机 活跃内存大小
+ (NSString *)getDeviceActiveMemory {
    // 获取当前主机的端口
    mach_port_t hostPort = mach_host_self();
    // 用于存储虚拟内存统计信息
    vm_statistics64_data_t vmStats;
    // 统计信息的数量
    mach_msg_type_number_t count = sizeof(vmStats) / sizeof(natural_t);

    // 调用 host_statistics64 函数获取系统的虚拟内存统计信息
    if (KERN_SUCCESS == host_statistics64(hostPort, HOST_VM_INFO64, (host_info64_t)&vmStats, &count)) {
        // 获取系统的页面大小
        vm_size_t pageSize = vm_page_size;
        // 计算活跃内存大小
        uint64_t activeMemory = (uint64_t)vmStats.active_count * pageSize;
        // 将活跃内存大小转换为字符串
        return [NSString stringWithFormat:@"%llu", activeMemory];
    } else {
        // 若获取失败，返回错误提示
        return @"";
    }
}

// 获取手机 不活跃内存大小
+ (NSString *)getDeviceNotActiveMemory{
    mach_port_t hostPort = mach_host_self();
    // 用于存储虚拟内存统计信息
    vm_statistics64_data_t vmStats;
    // 统计信息的数量
    mach_msg_type_number_t count = sizeof(vmStats) / sizeof(natural_t);

    // 调用 host_statistics64 函数获取系统的虚拟内存统计信息
    if (KERN_SUCCESS == host_statistics64(hostPort, HOST_VM_INFO64, (host_info64_t)&vmStats, &count)) {
        // 获取系统的页面大小
        vm_size_t pageSize = vm_page_size;
        // 计算不活跃内存大小
        uint64_t inactiveMemory = (uint64_t)vmStats.inactive_count * pageSize;
        // 将不活跃内存大小转换为字符串
        return [NSString stringWithFormat:@"%llu", inactiveMemory];
    } else {
        // 若获取失败，返回错误提示
        return @"";
    }
}

#pragma mark - 获取 userRandomKey
+ (NSString *)getUserRandomKey{
    NSString * randomKey = [GlobalMethod readUnprefixStrFromUserDefaults:LOCAL_USER_RANDOM_KEY];
    if(isStr(randomKey)){
        return randomKey;
    }else{
        // 创建一个新的UUID
        NSUUID *uuid = [[NSUUID alloc] init];
        NSString *uuidString = [uuid UUIDString];
        [GlobalMethod writeUnprefixStr:uuidString forKey:LOCAL_USER_RANDOM_KEY];
        return uuidString;
    }
}

#pragma mark - 设备最后一次启动时间
+ (NSInteger)getDeviceLastStartUpTime{
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    NSTimeInterval systemUptime = processInfo.systemUptime;
    NSDate *bootDate = [NSDate dateWithTimeIntervalSinceNow:(-1 * systemUptime)];
    NSTimeInterval timeInterval = [bootDate timeIntervalSince1970];
    NSTimeInterval milliseconds = timeInterval * 1000;
    NSInteger millisecondsSince1970 = (NSInteger)milliseconds;
    return millisecondsSince1970;
}

#pragma mark - 系统开机时间
+ (NSTimeInterval)getSystemStartUptime {
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != 0) {
        NSLog(@"Error in sysctl");
        return 0;
    }
    NSTimeInterval uptime = [[NSDate date] timeIntervalSince1970] - boottime.tv_sec;
    return uptime;
}

#pragma mark - 获取设备网络类型
+ (NSString *)getDeviceNetworkType{
    NSString * notReachable = @"none";
    struct sockaddr_storage zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.ss_len = sizeof(zeroAddress);
    zeroAddress.ss_family = AF_INET;
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;
    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    if (!didRetrieveFlags) {
        return notReachable;
    }
    BOOL isReachable = ((flags & kSCNetworkFlagsReachable) != 0);
    BOOL needsConnection = ((flags & kSCNetworkFlagsConnectionRequired) != 0);
    if (isReachable && !needsConnection) { }else{
        return notReachable;
    }
    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired ) {
        return notReachable;
    } else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
        CTTelephonyNetworkInfo * info = [[CTTelephonyNetworkInfo alloc] init];
        NSString *currentRadioAccessTechnology;
        if (info && [info respondsToSelector:@selector(serviceCurrentRadioAccessTechnology)]) {
            NSDictionary *radioDic = [info serviceCurrentRadioAccessTechnology];
            if (radioDic.allKeys.count) {
                currentRadioAccessTechnology = [radioDic objectForKey:radioDic.allKeys[0]];
            } else {
                return notReachable;
            }
        } else {
            return notReachable;
        }
        if (currentRadioAccessTechnology) {
            if (@available(iOS 14.1, *)) {
                if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNRNSA] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNR]) {
                    return @"5G";
                }
            }
            if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
                return @"4G";
            } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
                return @"3G";
            } else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
                return @"2G";
            } else {
                return @"other";
            }
        } else {
            return notReachable;
        }
    } else {
        return @"wifi";
    }
}

#pragma mark - 运营商无线接入技术
// 取字典第一个Value值
+ (NSString *)currentRadioAccessTechnology {
    CTTelephonyNetworkInfo *networkInfo = [[CTTelephonyNetworkInfo alloc] init];
    NSDictionary *currentRadioAccessTechnology = networkInfo.serviceCurrentRadioAccessTechnology;
    if ([currentRadioAccessTechnology count] > 0) {
        return [currentRadioAccessTechnology allValues].firstObject;
    } else {
        return @""; // 字典为空，返回nil
    }
}

#pragma mark - 获取 设备开机到现在的毫秒数
// 获取设备开机到现在的毫秒数 *1000 - (包含睡眠时间)
+ (uint64_t)getStartDeviceMillisecondsIncludingSleep {
    uint64_t uptime = mach_absolute_time();
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    uptime *= timebase.numer;
    uptime /= timebase.denom;
    uint64_t uptimeMilliseconds = uptime / 1000000;
    return  uptimeMilliseconds;
    double elapsedTime = CACurrentMediaTime();
    double elapsedTimeInMilliseconds = elapsedTime * 1000;
    return elapsedTimeInMilliseconds;
}

// 获取设备开机到现在的毫秒数 *1000 - (不包含睡眠时间)
+ (uint64_t)getStartDeviceMillisecondsExcludingSleep {
    // 获取自设备启动以来的实际运行时间，不包含睡眠时间
    struct timeval boottime;
    int mib[2] = {CTL_KERN, KERN_BOOTTIME};
    size_t size = sizeof(boottime);
    time_t now;
    time_t uptimeSeconds = 0;
    if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) {
        time(&now);
        uptimeSeconds = difftime(now, boottime.tv_sec);
    }
    uint64_t uptimeMilliseconds = uptimeSeconds * 1000;
    return uptimeMilliseconds;
}

#pragma mark - 判断 是否开启代理
+ (BOOL)isUsingProxy {
    NSDictionary *proxySettings = (__bridge NSDictionary *)CFNetworkCopySystemProxySettings();
    NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:DOMAIN_NAME]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));
    NSDictionary *settings = proxies.firstObject;
    NSString *proxyType = settings[(NSString *)kCFProxyTypeKey];
    if ([proxyType isEqualToString:(NSString *)kCFProxyTypeAutoConfigurationURL] ||
        [proxyType isEqualToString:(NSString *)kCFProxyTypeAutoConfigurationJavaScript] ||
        [proxyType isEqualToString:(NSString *)kCFProxyTypeHTTP] ||
        [proxyType isEqualToString:(NSString *)kCFProxyTypeHTTPS] ||
        [proxyType isEqualToString:(NSString *)kCFProxyTypeSOCKS]) {
        return YES;
    }
    return NO;
}

#pragma mark - 判断 是否使用vpn
+ (BOOL)isUsingVPN{
    NSDictionary * proxySettings = (__bridge NSDictionary *)CFNetworkCopySystemProxySettings();
    NSArray * keys = [proxySettings[@"SCOPED"] allKeys];
    for (NSString * key in keys) {
        if ([key rangeOfString:@"tap"].location != NSNotFound ||
            [key rangeOfString:@"tun"].location != NSNotFound ||
            [key rangeOfString:@"ppp"].location != NSNotFound) {
            return YES;
        }
    }
    return NO;
}

#pragma mark - 是否开启低电量模式
+ (BOOL)isLowPowerModeEnabled {
    if (@available(iOS 9.0, *)) {
        return [NSProcessInfo processInfo].isLowPowerModeEnabled;
    } else {
        // 如果设备不支持低电量模式，则始终返回 NO
        return NO;
    }
}

#pragma mark - 获取环境变量信息
+ (NSDictionary *)getEnvironmentVariables {
    return [[NSProcessInfo processInfo] environment];
}

#pragma mark - 获取启动参数（调试和命令行）
+ (NSArray<NSString *> *)getLaunchArguments {
    NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
    return arguments;
}

#pragma mark - 开关手电筒
+ (void)toggleFlashlight {
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    if (device && [device hasTorch]) {
        [device lockForConfiguration:nil];
        if (device.torchMode == AVCaptureTorchModeOff) {
            [device setTorchMode:AVCaptureTorchModeOn];
        } else {
            [device setTorchMode:AVCaptureTorchModeOff];
        }
        [device unlockForConfiguration];
    }
}

@end
